differential: compare initials() on roles-identical names (#484); fix the facade's dropped E/Y initial (#462) - #494
Merged
Conversation
…462) HumanName.initials() dropped a dotted or bare-capital E/Y in the middle or family group: 'Scott E. Werner' gave 'S. W.' since 2.0.0 where 1.4.0 gave 'S. E. W.'. v1's is_conjunction was 'in the set AND NOT is_an_initial'; the 2.0 facade kept the first half only. Restored with _render._INITIAL, v1's own initial shape, scoped to _process_initial. parse().initials() never had the bug. 14 corpus names come into 1.4.0 agreement; the differential cannot see it until the next commit gives it an initials column, where they carry a fix(#462) rule. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
) The gate compared the seven roles plus _ambiguities, so a render-layer change with every role identical was invisible to it by construction. Both surfaces now carry an _initials pseudo-field -- the facade's at every baseline, the core's from 2.0 on -- and it enters a name's diff only when the roles and ambiguity kinds agree: a role move drags its initials with it, so that movement is the role diff's consequence, not drift. Strict subset semantics were measured and rejected: they would have put _initials onto a long tail of existing rules for no added discrimination (the counts are in the decisions entry that lands with this PR). The report prints _initials only under main()'s own verdict, so an UNEXPLAINED block always pastes into a rule the validator accepts. What it surfaced, now classified with fields = ["_initials"] rules: the R2 all-particle readmission (27 names, three ledgers, shipped in 2.2.0 with a release note but no rule the gate could hold), #360's 'los' (1 name), and HumanName.initials() initialing each WORD of a joined run where 1.4.0 initialed the run as one group -- 98 names at 1.4.0, changed in 2.0.0 and recorded nowhere until now. AGENTS.md's release-note doctrine now says initials() is visible to the gate as a floor, not a population. The 14 names the facade's dropped E/Y initial moved (#462, fixed in the previous commit) now move against the three 2.x baselines instead and carry a fix(#462) rule in each, so the gate is green at all four baselines at this commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… R3 twin The decisions entry for #484: why _initials enters a diff only when the roles agree (strict semantics measured at 43 / 43 / 36 rules of churn for no discrimination), the three clusters it surfaced with their counts and tiers, why the per-word grouping is classified three minors late, and the recompute recipe with its mutation check. R3 gains the #462 bullet. Two pointer comments so the next reader of the case table's 'no initials column' note and the facade's 'not pinned' comment knows the differential now looks, and one ledger header clause reworded so #462 does not read as 2.2.0-era. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ires Four reviewers over the three commits. Documentation truth: the #462 names agree with 1.4.0 again since the fix, so two comments that said they diff there now say what the connective rule's two exclusions actually buy -- any future facade initials change on those shapes surfaces UNEXPLAINED at 1.4.0 rather than being absorbed as per-word grouping; R2, R3 and R4 carried the gate-cannot-see-initials limit in the present tense and gain dated amendments; the README's standing rule count is gone; _facade.py's "v1 parser.py:427 verbatim" says "after ..., not verbatim", the loop no longer being a textual copy; and the release bullet's John E Smith is a bare ASCII capital, since _render._INITIAL is ^(\w\.|[A-Z])$ and an undotted Cyrillic capital is not initial-shaped. The initials-view entry's own measured claims re-derived on the shipped tree: the 1.4.0 churn numerator (53 of 72, not 43), the 140 / 28 cluster totals dated to the pre-fix tree with the shipped tree's 126 / 42 / 42 / 14 beside them, two illustrations replaced by inputs that reproduce, the 14 given the population the bug could reach (14 of 14, the rule's regex reaching four more in leading position). The RECOMPUTE bullet splits into two recipes, because only one of them runs off the gate: the classified totals are the sum of the fields = ["_initials"] rules' heading counts, while the per-name split and the pre-fix figures need the in-memory run. One printer change, in both the UNEXPLAINED and the UNCLASSIFIED (radar) block, which share _print_field_diffs: it shows the core's initials movement when that differs from the facade's, the two being independent implementations -- with a test for the differing pair and one for the identical pair the print-once convention still covers. The bound-given rule's ordering rationale is measured rather than asserted: TWO corpus names carry both a bound word and a particle chain, not three, and neither has an `_initials` diff -- the third name the note counted shares with the Ph. D. rule. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #494 +/- ##
=======================================
Coverage 98.66% 98.66%
=======================================
Files 45 45
Lines 3218 3219 +1
=======================================
+ Hits 3175 3176 +1
Misses 43 43 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…gers Four review agents over PR #494. Ledger comments: a precedent that cited a rule the 1.4.0 ledger does not have (fix(#445) is the name-list precedent there), planning labels and a false narrow-first claim in the _initials block header, 'Ph. D., Jr.' diffs on roles not nothing, the particle-chain gloss named a middle that is a family, and the 14 dated with the invariant behind the other four. All THIRTEEN _initials rules gain orders = ["DEFAULT"] -- six at 1.4.0, three each at 2.0.0 and 2.1.0, one at 2.2.0: each describes a default-order render, and an order-bearing entry never consults the facade, so a core-side family-first regression must not be absorbed under a rule whose prose says facade. compare.py: a docstring clause named the wrong branch; the validator's mixed-fields message printed an empty list on a duplicated _initials; the _RULE_FIELDS comment gains the ambiguity kinds. Tests: the fixture refuses unknown row keys (a misspelled _initials would otherwise default to the tree's value and silently agree); five gap tests -- the radar block, the order-bearing path, the guard's v2 half, facade-moved-core-agreed, and a surface-distinguishing name for the exec'd worker test; the facade fix pinned on a group that used to vanish and on the bare-Cyrillic boundary. Docs: the release headline says middle- or family-group; R4's 140 split into 126 + 14; the given group, not leading position, is the discriminator; AGENTS.md counts entries, not names. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Review round 2 conditioned the mixed-_initials check on the OTHER names in `fields`, which made `["_initials", "_initials"]` pass where it had been refused with an empty-list message. classify() reads `fields` as a set, so a repeat matches nothing more; it is a copy-paste slip that every check below would otherwise swallow, and the `_initials` check in particular would read the pair as `_initials` alone. Both validators now refuse it, with a row in each rejection table. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #484. Closes #462.
What
tools/differential/compare.pygains an_initialspseudo-field on both surfaces (the facade's at every baseline, the core's from 2.0 on). It enters a name's diff only when the seven roles and_ambiguitiesagree: a role move drags its initials with it, so that movement is the role diff's consequence, not render drift. Strict subset semantics were measured and rejected (53 / 43 / 36 existing rules at 1.4.0 / 2.0.0 / 2.1.0 would have needed_initialsfor no added discrimination). A rule listing_initialslists nothing else; the validator refuses the mix. The report prints_initialsonly under main()'s own verdict, so an UNEXPLAINED block always pastes into a rule the validator accepts.fields = ["_initials"]rules: the R2 all-particle readmission (27 names, three ledgers -- shipped in 2.2.0 with a release note but no rule the gate could hold),Mc DonaldandSte Marieread the particle as the given name #360'slos(1), and the facade initialing each WORD of a joined run since 2.0.0 where 1.4.0 grouped the run (98 names at 1.4.0, never recorded -- classified late, with a 2.3.0 release bullet saying so; four rules because the Latin-alternation guard admits one copied vocabulary per rule).HumanName('Scott E. Werner').initials()drops the middle initial — the facade readsEas the conjunction #462:HumanName.initials()dropped a dotted or bare-capitalE/Ymiddle initial since 2.0.0 (Scott E. Werner->S. W.); v1's conjunction test excluded initial-shaped words and the facade's did not. Restored with_render._INITIAL, scoped to_process_initial. 14 corpus names come into 1.4.0 agreement;parse().initials()was already right.initials()is visible to the gate as a floor, not a population (measured 83 / 28 / 55 at 2.1.0); R2, R3 and R4 gain dated amendments retiring the gate-cannot-see-initials limit; a new decisions entry,differential-ledger, the initials view, carries the semantics, the three clusters, and the recompute recipe.Measured
Gate exit 0 at 1.4.0 / 2.0.0 / 2.1.0 / 2.2.0, unexplained 0, radar unclassified 0; intentional totals 226 / 205 / 113 / 0 -> 352 / 247 / 155 / 14, exactly the new rules' explained counts (27+1+66+19+11+2; 27+1+14; 27+1+14; 14). Mutation run: with the roles-identical guard removed, 117 role-moving names lose their rule on the shipped tree (143 before the
_initialsrules existed), so the guard is live. Suite: 6429 passed.Commits (each green on its own)
fix(facade):HumanName('Scott E. Werner').initials()drops the middle initial — the facade readsEas the conjunction #462, its v1-bank tests, the release bullet. The gate cannot see initials yet, so it is unchanged here.tooling(differential): the pseudo-field, its tests, README, AGENTS.md, all seven rules with their guard rosters, the per-word release bullet. Green at all four baselines.docs(design): the decisions entry, the R3 bullet, two pointer comments.review round: four reviewers' findings -- the entry's own numbers re-derived on the shipped tree, the R2/R3/R4 amendments, a printer change showing the core's initials movement when it differs from the facade's, with its tests.Spec:
docs/superpowers/specs/2026-09-01-initials-pseudo-field-design.md(gitignored, main checkout).Follow-up worth its own issue (not filed):
_CORPUS_CLAIMSrecords a rule's regex REACH, not its explained count, so a rule that goes from explaining 14 names to 2 stays green until it explains zero; a dated explained-count dimension on_Claimwould pin it.🤖 Generated with Claude Code